#include "sqlconnpool.h"
#include "make_log.h"
using namespace std;

atomic<SqlConnPool*> SqlConnPool::connPool;
mutex SqlConnPool::m_mutex;

SqlConnPool::SqlConnPool()
{
    userCount_ = 0;
    freeCount_ = 0;
}

SqlConnPool* SqlConnPool::getInstance()
{   
    SqlConnPool* pool = connPool.load();
    if(pool == nullptr)
    {
        lock_guard<mutex> locker(m_mutex);
        pool = connPool.load();
        if(pool == nullptr)
        {
            pool = new SqlConnPool;
            connPool.store(pool);
        }
    }
    return pool;
}

void SqlConnPool::Init(const char* host, int port, const char* user, const char* pwd, const char* dbName, int connSize)
{
    assert(connSize > 0);
    for(int i = 0; i < connSize; ++i)
    {
        MYSQL* sql = nullptr;
        sql = mysql_init(sql);
        if(!sql)
        {
            LOG("mysql init error!");
            assert(sql);
        }
        sql = mysql_real_connect(sql, host, user, pwd, dbName, port, NULL, 0);
        if(!sql)
        {
            LOG("Mysql Connect error!");
        }
        connQue_.push(sql);
        sem_init(&semId_, 0, MAX_CONN_);
    }
}

MYSQL* SqlConnPool::GetConn()
{
    MYSQL* sql = nullptr;
    if(connQue_.empty())
    {
        LOG("SqlConnPool busy!");
        return NULL;
    }

    sem_wait(&semId_);

    {
        lock_guard<mutex> locker(mtx_);
        sql = connQue_.front();
        connQue_.pop();
    }
    return sql;
}

void SqlConnPool::FreeConn(MYSQL* sql)
{
    assert(sql);
    lock_guard<mutex> locker(mtx_);
    connQue_.push(sql);
    sem_post(&semId_);
}

void SqlConnPool::ClosePool()
{
    lock_guard<mutex> locker(mtx_);
    while(!connQue_.empty())
    {
        auto item = connQue_.front();
        connQue_.pop();
        mysql_close(item);
    }
    mysql_library_end();
}

int SqlConnPool::GetFreeConnCount()
{
    lock_guard<mutex> locker(mtx_);
    return connQue_.size();
}

SqlConnPool::~SqlConnPool()
{
    ClosePool();
}